/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.cmp.player.abilities;

import com.cmp.player.controls.CursorSelectionControl;
import com.cmp.player.controls.MoveControl;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;

/**
 * Gives the node the functions to use an ability.
 * Includes cooldown functionality.
 * @author krummer
 */
public abstract class AbilityControl extends AbstractControl {
    private static final String GCD_KEY = "globalCD";
    private String userDataKeyCD;
    private String userDataKeyCAST;
    private float max_cooldown;
    private float max_casttime;
    private float max_gcd;
    
    @Override
    public void setSpatial(Spatial spatial) {
        super.setSpatial(spatial);
        userDataKeyCD = this.getClass().toString() + "CD";
        userDataKeyCAST = this.getClass().toString() + "DUR";
        
        //init shit.
        this.setGlobalCD(1.f);
        
        this.setCooldown(0.f);
        this.setCastDuration(0.f);
        this.activateCastTime();
        this.finishCast();
        this.activateCooldown();
        this.activateGCD();
        
    }
    
    /**
     * max ast time.
     * @param dur how long it takes to cast ability.
     */
    public void setCastDuration(float duration) {
        this.max_casttime = duration;
    }
    
    /**
     * Cast time left
     */
    public float getCastDuration() {
        return super.getSpatial().getUserData(userDataKeyCAST);
    }
    
    /**
     * makes the ability go on cooldown.
     */
    public void activateCooldown() {
        super.getSpatial().setUserData(this.userDataKeyCD, this.max_cooldown);
    }
    
    /**
     * makes all abilites go on global cd.
     */
    public void activateGCD() {
        super.getSpatial().setUserData(GCD_KEY, this.max_gcd);
    }
    
    /**
     * Disable all movement during cast.
     */
    public void activateCastTime() {
        this.lockMove(true);
        super.getSpatial().setUserData(this.userDataKeyCAST, this.max_casttime);
    }
    
    /**
     * unlock the movements.
     */
    private void finishCast() {
        //lock movements if necessary.
        this.lockMove(false);
    }
    
    /**
     * roots available movement controls.
     * @param lock switch.
     */
    private void lockMove(boolean lock) {
        //lock movements if necessary.
        CursorSelectionControl cursor = this.getSpatial().getControl(CursorSelectionControl.class);
        MoveControl move = this.getSpatial().getControl(MoveControl.class);
        
        if(cursor != null) {
            cursor.setRooted(lock, this.max_casttime);
        }
        if(move != null) {
            String name = this.getSpatial().getName();
            move.setRooted(lock, this.max_casttime);
        }
    }
    
    /**
     * Set the max cooldown time of the ability.
     */
    public void setCooldown(float cd) {
        this.max_cooldown = cd;
    }
    
    /**
     * get current cooldown time
     */
    public float getCooldown() {
        //Save class name plus CD to distinquish between the abilities.
        return super.getSpatial().getUserData(this.userDataKeyCD);
    }
    
    /**
     * Set the global ability cd.
     */
    public void setGlobalCD(float cd) {
        this.max_gcd = cd;
    }
    
    /**
     * get current cooldown time
     */
    public float getGlobalCD() {
        //Save class name plus CD to distinquish between the abilities.
        return super.getSpatial().getUserData(GCD_KEY);
    }
    
    /**
     * Check if the CD is active.
     * @return is on cooldown
     */
    public boolean isOnCooldown() {
        return ((this.getCooldown() > 0.f) || (this.getGlobalCD() > 0.f));
    }
    
    /**
     * Check if ability is casting.
     * @return is casting
     */
    public boolean isCasting() {
        return (this.getCastDuration() > 0.f);
    }
    
    @Override
    protected void controlUpdate(float tpf){
        //TODO: optimize cooldown calculations.
        if(this.isOnCooldown()) {
            float newCD = this.getCooldown() - tpf;
            if(newCD < 0.f) {
                newCD = 0.f;
            }
            this.getSpatial().setUserData(this.userDataKeyCD, newCD);
            
            
            float newGCD = this.getGlobalCD() - tpf;
            if(newGCD < 0.f) {
                newGCD = 0.f;
            }
            this.getSpatial().setUserData(GCD_KEY, newGCD);
        }
        
        /*if(this.isCasting()) {
            float newDUR = this.getCastDuration() - tpf;
            if(newDUR < 0.f) {
                newDUR = 0.f;
                this.finishCast();
            }
            this.getSpatial().setUserData(this.userDataKeyCAST, newDUR);
        }*/
    }
    
    /**
     * Ability functionality goes here.
     */
    public abstract void execute();
}
